#include "RealDealTable.h"

#include <bondlib/BondCDCPriceInfo.h>
#include <bondlib/BondCSIPriceInfo.h>
#include <bondlib/BondCalendar.h>
#include <core/StyleMgr.h>
#include <include/CmdDefines.h>
#include <qbtools/tools.h>
#include <uam/ServerTimeMgr.h>
#include <uam/UserAccountManager.h>
#include <widgets/STabCtrl.h>
#include <widgets/table/STable.h>
#include <widgets/table/STableColumnSet.h>

#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QHeaderView>
#include <QMenu>
#include <QTableView>
#include <QTimer>
#include <QVBoxLayout>

#include "../BestQuote/BestPriceFormat.h"
#include "../BondColDelegate.h"
#include "../BondDataCenter.h"
#include "../BondUtility.h"
#include "../Detail/BondDetailDlg.h"
#include "../Filter/EnviFilter.h"
#include "../GridImage.h"
#include "../QbBondModule.h"
#include "../SSBizTool.h"
#include "../StringResource.h"
#include "RealTimeDealFilter.h"
#include "RealTimeDealModel.h"

static int getSortKey(int nDefCol, bool isEnglish) {
  // 参考int CDlgQuoteV2::GetSortKey( int nDefCol )
  switch (nDefCol) {
    case COL_FLAG:
      return VBOND_NULL;  // 标志项
    case COL_TTM:
      return VEXPIRY_DATE;  // 剩余期限
    case COL_CODE:
      return VBOND_CODE;  // 代码
    case COL_NAME:
      return isEnglish ? VSHORT_NAME_EN : VSHORT_NAME;  // 简称
    case COL_TKN_CLEANPRICE:
      return kTknPrice;  // 成交
    case COL_COUPON_RATE:
      return kCouponRate;  // 票面利率
    case COL_RATE_TYPE:
      return kRateType;  // 票面
    case COL_CDCVAL_PRE:
      return VESTBPRICEPRE;  // 昨日中债估值
    case COL_CDCVAL_TODAY:
      return VESTBPRICETODAY;  // 今日中债估值
    case COL_DEAL_CDC:
      return kDeal_Cdc;  // 成交-中债
    case COL_CDC_CLEANPRICE:
      return kCdcCleanPrice;  // 中债净价
    case COL_DURATION:
      return kDuration;  // 久期
    case COL_ISSUER_RATE:
      return VISSUERRATING;
    case COL_BOND_RATE:
      return VBONDRATING;
    case COL_CDC_RATING:
      return VCDCRATING;
    case COL_CSI_RATING:
      return VCSIRATING;
    case COL_CBR_RATING:
      return VCBRRATING;
    case COL_OUTLOOK:
      return kOutlook;  // 展望
    case COL_CSIVAL:
      return kCsiVal;  // 中证估值
    case COL_DEAL_CSI:
      return kDeal_Csi;  // 成交-中证
    case COL_CSI_CLEANPRICE:
      return kCsiCleanPrice;  // 中证净价
    case COL_OPTION_TYPE:
      return kOptionType;  // 含权类型
    case COL_OPTION_DATE:
      return kOptionDate;  // 行权日
    case COL_MATURITY_DATE:
      return kMaturityDate;  // 到期日
    case COL_TERM_TO_MATURITY:
      return TERM_TO_MATURITY;
    case COL_CROSSMARKET:
      return kCrossMarket;  // 跨市场
    case COL_INDUSTRY:
      return isEnglish ? kIndustryEn : kIndustry;  // 行业
    case COL_RATINGAGENCY:
      return kRatingAgency;  // 评级机构
    case COL_BOND_GUARANTOR:
      return isEnglish ? kBondGuarantorEn : kBondGuarantor;  // 担保人
    case COL_OUTSTANDING_AMOUNT:
      return kOutstandingAmount;  // 债券余额（亿）
    case COL_ISSUE_TYPE:
      return VBondIssueType;  // 发行
    case COL_MUNICIPAL_BOND:
      return VMunicipalBond;  // 地方债类型
    case COL_BOND_TYPE:
      return VBondType;
    case COL_BOND_ISSUER:
      return VBondIssuer;
    case COL_CORP:
      return VBROKERKEY;  // 公司Broker
    case COL_UPDATETIME:
      return VMODIFY_TIME;  // 更新时间
  }
  return VBOND_NULL;
}

using namespace detail;
RealDealTable::RealDealTable(QWidget* parent) : QWidget(parent) {
  QVBoxLayout* mainLayout = new QVBoxLayout(this);
  mainLayout->setContentsMargins(0, 0, 0, 0);
  mainLayout->setSpacing(4);

  m_dealTable = new SVirtualTable(this);
  m_model = new DefaultTableModel(this);
  m_model->setTable(m_dealTable);
  mainLayout->addWidget(m_dealTable);

  m_dealTable->setHeaderSortable(true);
  m_dealTable->table()->setModel(m_model);
  m_dealTable->table()->horizontalHeader()->setSectionResizeMode(
      QHeaderView::Interactive);
  m_dealTable->table()->horizontalHeader()->setSectionsMovable(true);
  m_dealTable->table()->horizontalHeader()->show();
  m_dealTable->table()->setContextMenuPolicy(Qt::CustomContextMenu);

  initTable();

  RemainDateDelegate* remainDateDelegate =
      new RemainDateDelegate(m_dealTable, m_tableSet, TopCursor);
  m_dealTable->table()->setItemDelegateForColumn(COL_TTM, remainDateDelegate);

  BrokerCorpDelegate* brokerCorpDelegate = new BrokerCorpDelegate(m_dealTable);
  m_dealTable->table()->setItemDelegateForColumn(COL_CORP, brokerCorpDelegate);

  QTimer::singleShot(100, [=]() {
    connect(&BondDataCenter::instance(), &BondDataCenter::dealMarketPushAll,
            this, &RealDealTable::onDealMarketPushAll);
    connect(m_dealTable, &SVirtualTable::viewPosChanged,
            [=](int) { updateTable(); });
  });

  connect(m_dealTable->table(), &QTableView::customContextMenuRequested, this,
          &RealDealTable::onContextMenu);
  connect(m_dealTable, &SVirtualTable::headerSort, this,
          &RealDealTable::onHeaderSort);
  connect(m_dealTable->table(), &QTableView::clicked, this,
          &RealDealTable::onRealDealRowClicked);
  connect(m_dealTable->table(), &QTableView::doubleClicked, this,
          &RealDealTable::onRealDealRowDblClicked);

  m_dealModel = new RealTimeDealModel();
  m_dealModel->GetSortInfo().InitData(VMODIFY_TIME);
  m_dealModel->setFlaser(this);

  m_dealIndex = new CBondInfo;
  m_dealRecord = new MarketStreamInfo;

  onBrokerSelChanged();
}

void RealDealTable::setFilterCondition(FilterCondition* pFilterCond) {
  if (pFilterCond) m_stuFilterCondition = *pFilterCond;
  m_pFilterCondtion = &m_stuFilterCondition;
}

bool RealDealTable::isBrokerCheckEnable() const {
  // 判断是否要检查每个记录的经纪商个数
  if (m_nCorpID != 0) return false;
  if (m_pEnviFilter &&
      m_pEnviFilter->m_nFilterType == FilterType::FilterType_Search) {
    if (m_pFilterCondtion &&
        m_pFilterCondtion->strSearch.length() > 0)  // 搜索模式下，并且有输入
      return true;
  }
  return false;
}

void RealDealTable::changeParam(bool showAll, int nCorpID /*= -999*/) {
  if (nCorpID == -999) nCorpID = m_nCorpID;
  if (m_nCorpID != nCorpID) m_nCorpID = nCorpID;

  if (m_pEnviFilter->m_nFilterType == FilterType::FilterType_BondAndCondition) {
    if (m_pFilterCondtion != nullptr) {
      BLHCONDITION blh = m_pFilterCondtion->stBlh;
      blh.nMatFlg = 0;
      std::string sGroupID = m_pFilterCondtion->strGroupID.toStdString();
      m_dealModel->GetFilter()->SetConditionAndAttention(sGroupID, blh,
                                                         m_nCorpID);
    }
  } else if (m_bUseTempCondition) {
    BondsFilter bf;
    bf.stBlh = *m_pBlh;
    FIELDCOPY(bf.stBlh.sCompanyid, "1");

    BLHCONDITION blh = *m_pBlh;
    blh.nMatFlg = 0;
    m_dealModel->GetFilter()->SetCondition(blh, m_nCorpID);
  } else if (m_pEnviFilter->m_nFilterType == FilterType::FilterType_Bond) {
    // 通过关注债券来过滤
    std::string sGroupID = m_pEnviFilter->m_strId.toStdString();
    m_dealModel->GetFilter()->SetAttention(sGroupID, m_nCorpID);
  } else if (m_pEnviFilter->m_nFilterType == FilterType::FilterType_Search) {
    // 通过查找关键字来过滤
    if (m_pFilterCondtion != NULL) {
      m_dealModel->GetFilter()->SetConditionAndSearch(
          m_pFilterCondtion->strSearch.toStdString(),
          m_pFilterCondtion->nSearchType, m_pFilterCondtion->stBlh, m_nCorpID);
    }
  }
  m_dealModel->OnFilter(isBrokerCheckEnable());

  if (showAll) {
    m_dealModel->GetSortInfo().InitData(VMODIFY_TIME);
  }
  m_selRowKey.clear();
  m_dealModel->OnSort();
  updateTable(true);
  updateSpecialListWidth();
}

void RealDealTable::onFilterChange(bool v) { m_bUseTempCondition = v; }

void RealDealTable::addFlash(std::string id) {
  FlashInfo fi;
  fi.id = QString::fromStdString(id);
  m_dealTable->addFlashInfo(fi, false);
}

void RealDealTable::removeFlash(std::string id) {
  FlashInfo fi;
  fi.id = QString::fromStdString(id);
  m_dealTable->removeFlashInfo(fi);
}

void RealDealTable::initTable() {
#define ALIGN_RIGHT (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignRight)
#define ALIGN_LEFT (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignLeft)
#define ALIGN_CENTER (Qt::Alignment)(Qt::AlignVCenter | Qt::AlignCenter)

  m_tableSet = new STableColumnSet(m_dealTable, "BestPriceRealDeal", this);
  m_tableSet->setSaveCfg(true);

  BEGIN_COLUMN;
  ADD_COLUMN(0, m_tableSet, "", 0, 30, 30, 0.09, false, ALIGN_LEFT, kFixed, "");
  m_cols.push_back(COL_FLAG);

  ADD_COLUMN(COL_CORP, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CORP), 0, 68, 12, 0.09,
             false, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_CORP);

  ADD_COLUMN(COL_TTM, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_TTM), 0, 100, 12, 0.09,
             false, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_TTM);

  ADD_COLUMN(COL_CODE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CODE), 0, 120, 12,
             0.09, false, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_CODE);

  ADD_COLUMN(COL_NAME, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_NAME), 0, 150, 12,
             0.12, false, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_NAME);

  ADD_COLUMN(COL_TKN_CLEANPRICE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_TKN_CLEANPRICE), 1, 60,
             12, 0.09, false, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_TKN_CLEANPRICE);

  ADD_COLUMN(COL_COUPON_RATE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_COUPON_RATE), 0, 75,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_COUPON_RATE);

  ADD_COLUMN(COL_RATE_TYPE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_RATE_TYPE), 0, 75, 12,
             0.09, true, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_RATE_TYPE);

  // TODO:上证固收
  ADD_COLUMN(COL_CDCVAL_PRE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CDCVAL_PRE), 2, 100,
             12, 0.11, false, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CDCVAL_PRE);

  ADD_COLUMN(COL_CDCVAL_TODAY, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CDCVAL_TODAY), 2, 100,
             12, 0.11, false, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CDCVAL_TODAY);

  ADD_COLUMN(COL_DEAL_CDC, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_DEAL_CDC), 2, 100, 12,
             0.11, false, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_DEAL_CDC);

  ADD_COLUMN(COL_CDC_CLEANPRICE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CDC_CLEANPRICE), 2, 80,
             12, 0.11, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CDC_CLEANPRICE);

  ADD_COLUMN(COL_DURATION, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_DURATION), 2, 72, 12,
             0.09, true, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_DURATION);

  ADD_COLUMN(COL_ISSUER_RATE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_ISSUER_RATE), 0, 60,
             12, 0.09, false, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_ISSUER_RATE);

  ADD_COLUMN(COL_BOND_RATE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_BOND_RATE), 0, 60, 12,
             0.09, false, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_BOND_RATE);

  ADD_COLUMN(COL_CDC_RATING, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CDC_RATING), 2, 75, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CDC_RATING);

  ADD_COLUMN(COL_CSI_RATING, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CSI_RATING), 2, 75, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CSI_RATING);

  ADD_COLUMN(COL_CBR_RATING, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CBR_RATING), 2, 75, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CBR_RATING);

  ADD_COLUMN(COL_OUTLOOK, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_OUTLOOK), 0, 53, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_OUTLOOK);

  ADD_COLUMN(COL_CSIVAL, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CSIVAL), 2, 75, 12,
             0.11, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CSIVAL);

  ADD_COLUMN(COL_DEAL_CSI, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_DEAL_CSI), 2, 78, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_DEAL_CSI);

  ADD_COLUMN(COL_CSI_CLEANPRICE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CSI_CLEANPRICE), 2, 80,
             12, 0.11, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CSI_CLEANPRICE);

  ADD_COLUMN(COL_OPTION_TYPE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_OPTION_TYPE), 0, 80,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_OPTION_TYPE);

  ADD_COLUMN(COL_OPTION_DATE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_OPTION_DATE), 0, 95,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_OPTION_DATE);

  ADD_COLUMN(COL_MATURITY_DATE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_MATURITY_DATE), 0, 95,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_MATURITY_DATE);

  ADD_COLUMN(COL_TERM_TO_MATURITY, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_TERM_TO_MATURITY), 0,
             95, 12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_TERM_TO_MATURITY);

  ADD_COLUMN(COL_CROSSMARKET, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_CROSSMARKET), 0, 40,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_CROSSMARKET);

  ADD_COLUMN(COL_INDUSTRY, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_INDUSTRY), 0, 80, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_INDUSTRY);

  ADD_COLUMN(COL_RATINGAGENCY, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_RATINGAGENCY), 0, 94,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_RATINGAGENCY);

  ADD_COLUMN(COL_BOND_GUARANTOR, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_BOND_GUARANTOR), 0, 94,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_BOND_GUARANTOR);

  ADD_COLUMN(COL_OUTSTANDING_AMOUNT, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_OUTSTANDING_AMOUNT), 0,
             94, 12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_OUTSTANDING_AMOUNT);

  ADD_COLUMN(COL_ISSUE_TYPE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_ISSUE_TYPE), 0, 94, 12,
             0.09, true, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_ISSUE_TYPE);

  ADD_COLUMN(COL_MUNICIPAL_BOND, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_MUNICIPAL_BOND), 0, 94,
             12, 0.09, true, ALIGN_LEFT, kAuto, "");
  m_cols.push_back(COL_MUNICIPAL_BOND);

  ADD_COLUMN(COL_BOND_TYPE, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_BOND_TYPE), 0, 94, 12,
             0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_BOND_TYPE);

  ADD_COLUMN(COL_BOND_ISSUER, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_BOND_ISSUER), 0, 94,
             12, 0.09, true, ALIGN_RIGHT, kAuto, "");
  m_cols.push_back(COL_BOND_ISSUER);

  ADD_COLUMN(COL_UPDATETIME, m_tableSet,
             NewStringTable::strMarketTknWndListHead(COL_UPDATETIME), 0, 80, 12,
             0.09, false, ALIGN_CENTER, kAuto, "");
  m_cols.push_back(COL_UPDATETIME);

  m_tableSet->apply();
}

static bool IsEmpty(const char* str) {
  // 旧代码是 strlen(str)<=0;
  return str == nullptr || *str == '\0';
}

static void FormatPrice(QString& strTemp, const char* ctPrice) {
  if (ctPrice[0] == '\0') {
    strTemp = "--";
  } else {
    strTemp = SSTools::FormatePrice(ctPrice);
  }
}
static QString GetCleanPrice(const MarketStreamType2Body& body,
                             const CBondInfo* pBondInfo) {
  QString strSemiQuote, strPrice, temp;

  int nSemiType = SSTools::getSemiQuote(body.m_rebate, body.m_return_point,
                                        body.m_price, strSemiQuote);
  if (body.m_yield[0] == '\0') return "";

  if (atoi(body.m_quotetype) != 3 &&
      (pBondInfo->IsBondABS() || pBondInfo->IsTransBond())) {
    double dt = atof(body.m_yield);
    if (dt <= 0 || dt >= 30) return "";
  }
  FormatPrice(strPrice, body.m_yield);

  // nSemiType,strPrice,strSemiQuote
  switch (nSemiType) {
    case 0:
      temp = strSemiQuote;
      break;
    case -1:
    case 1:
    default:
      temp = strPrice;
      break;
      break;
  }
  return temp;
}

void RealDealTable::updateTable(bool reset, int selRow) {
  m_dealTable->clearTable();

  int pageCount = m_dealTable->pageCount();
  int pos = reset ? 0 : m_dealTable->sliderPos();

  if (m_dealModel->GetSortInfo().HasSortKey(VBOND_NULL)) {
    m_dealModel->GetSortInfo().InitData(VMODIFY_TIME);
    m_dealModel->OnSort();
  }

  MarketStreamInfo records[256];
  int count = m_dealModel->GetRecords(pos, pageCount, records);
  m_dealTable->setRealDataCount(m_dealModel->GetCount());

  QFont f = font();
  f.setPixelSize(14);
  f.setWeight(QFont::Normal);
  //	f.setBold(true);

  QFont timeF = f;
  timeF.setPixelSize(14);

  for (int row = 0; row < count; ++row) {
    const MarketStreamInfo& msi = records[row];
    const MarketStreamType2Body& Body = msi.m_body;
    bool deal_cancel = msi.IsDealStatusCanceled();

    int bid = CBondContainer::instance().GetBondIndex(
        msi.m_body.m_bondkey, msi.m_body.m_listedmarket);
    if (!CBondContainer::instance().IsValidIndex(bid)) continue;
    const CBondInfo& bondInfo = CBondContainer::instance().ElementAtR(bid);
    bool hasCDCAuth = bondInfo.IsCDCAuthValid();

    for (size_t col = 0; col < m_cols.size(); ++col) {
      if (!m_tableSet->isColVisible(col)) continue;

      QStandardItem* item = m_model->item(row, col);
      if (item == nullptr) item = new QStandardItem();

      item->clearData();

      ETknPriceColType colType = m_cols[col];
      if (COL_TTM == colType || COL_CODE == colType || COL_NAME == colType) {
        item->setData(StyleMgr::instance().color("TabSelBorder"),
                      Qt::ForegroundRole);
      } else {
        item->setData(StyleMgr::instance().color("TextNormal"),
                      Qt::ForegroundRole);
      }

      item->setData((int)(Qt::AlignLeft | Qt::AlignVCenter),
                    Qt::TextAlignmentRole);

      if (row % 2 == 0) {
        item->setData(StyleMgr::instance().color("BackNormal"),
                      Qt::BackgroundRole);
      } else {
        item->setData(StyleMgr::instance().color("BasicPlate"),
                      Qt::BackgroundRole);
      }

      if (deal_cancel) {
        item->setData(StyleMgr::instance().color("DealCanel"),
                      Qt::ForegroundRole);
        item->setData(StyleMgr::instance().color("BackNormal"),
                      Qt::BackgroundRole);
      }
      item->setData(f, Qt::FontRole);
      QString idStr = QString::fromLocal8Bit(msi.m_body.m_id);
      item->setData(idStr, DataIdRole);

      if (selRow != -1 && row == selRow) {
        m_selRowKey = idStr;
        item->setData(idStr, DataSelIdRole);
      } else if (!m_selRowKey.isEmpty()) {
        item->setData(m_selRowKey, DataSelIdRole);
      } else {
        item->setData("", DataSelIdRole);
      }

      switch (colType) {
        case COL_FLAG: {
          int nMsgType = atoi(msi.m_type);
          int nType =
              BondUtility::makeTypeOperate(nMsgType, atoi(msi.m_operate));
          item->setData(BondUtility::gridImage((EnumImgFlag)nType),
                        Qt::DecorationRole);
        } break;
        case COL_TTM: {
          QString txt = QString::fromLocal8Bit(
              bondInfo.GetRemainPeriod(ServerTimeMgr::instance().serverTime()));
          item->setData(txt, Qt::DisplayRole);

          int holidayType = emHolidayNull;
          QString strHolidayDays;
          bool isCIB = true;
          int nDayCIB = 0, nDaySSE = 0;
          if (CBondCalendar::instance().IsHoliday_CHY(bondInfo, isCIB, nDayCIB,
                                                      nDaySSE)) {
            if (isCIB) {
              if (nDayCIB == nDaySSE)
                strHolidayDays = QString::number(nDayCIB);
              else
                strHolidayDays = QString("%1/%2").arg(nDayCIB).arg(nDaySSE);
              holidayType = emHolidayCib;
            } else {
              holidayType = emHolidaySSE;
              strHolidayDays = QString::number(nDaySSE);
            }
            item->setData(holidayType, HolidayTypeRole);  // 存休息类型
            item->setData(strHolidayDays, HolidayNumberRole);  // 存休息时间

            int maturityDay = atoi(bondInfo.GetMaturityDate());
            item->setData(maturityDay, MaturityDayRole);
          }
        } break;
        case COL_CODE:
          item->setData(QString::fromLocal8Bit(bondInfo.GetCombBondCode()),
                        Qt::DisplayRole);
          break;
        case COL_NAME: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetBondShortName());
          if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0) {
            if (strcmp(bondInfo.GetEntCor(), "SMB") == 0)
              txt += tr("(一般)");
            else if (strcmp(bondInfo.GetEntCor(), "NMB") == 0)
              txt += tr("(专项)");
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_TKN_CLEANPRICE: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          item->setData(StyleMgr::instance().color("InnerBorder"),
                        Qt::ForegroundRole);
          QString tips;
          QString txt = SSTools::FormatePrice(Body.m_price);

          QString strSemiQuote;
          int semiType = SSTools::getSemiQuote(
              Body.m_rebate, Body.m_return_point, Body.m_price, strSemiQuote);

          QString strTips;
          if (strcmp(bondInfo.GetOptionType(), "NON") != 0 &&
              !IsEmpty(bondInfo.GetOptionType())) {
            int optType = 0;
            if (Body.m_exercise[0] == '0')
              optType = 1;
            else if (Body.m_exercise[0] == '1')
              optType = 2;

            if (optType !=
                0)  // optType为0，即Body.m_exercise[0]为空,代表无标签和tips
            {
              strTips = NewStringTable::strEstRemark(optType);
            }
          }

          bool exerciseSurfix = !strTips.isEmpty();
          bool bForward = strcmp(Body.m_settlementType, "FWD") == 0;
          if (bForward) {
            if (exerciseSurfix) {
              strTips.append(tr("，"));
            }
            strTips.append(tr("远期："));
            strTips.append(Body.m_settlementDescription);
          }
          if (exerciseSurfix) {
            item->setData(strTips, Qt::ToolTipRole);
            item->setData(BondUtility::gridImage(grid_flag_triangle),
                          Qt::DecorationRole);
          }
          if (bForward) {
            item->setData(strTips, Qt::ToolTipRole);
            item->setData("远", PostfixTxtRole);
            item->setData(QRect(0, 0, 14, 14), PostfixTxtRectRole);
            item->setData(StyleMgr::instance().color("InnerBorder"),
                          PostfixTxtRectColor);
          }

          if (deal_cancel)
            item->setData(BondUtility::gridImage(grid_bid_cancel),
                          Qt::DecorationRole);

          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          item->setData(txt, Qt::DisplayRole);

          // TODO:
        } break;
        case COL_COUPON_RATE: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = QString::fromLocal8Bit(bondInfo.GetCouponRateCurrent());
          int index = txt.indexOf(".");
          if (index > 0) {
            txt = txt.left(index + 3);
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_RATE_TYPE: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetRateType());
          if (txt.compare("FIXED") == 0) {
            // if(m_isEnglish){}
            txt = "固息";
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CDCVAL_PRE:
        case COL_CDCVAL_TODAY: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          int nOptType = CBondCDCPriceInfo::est_type_invalid;
          QString txt = "";
          if (hasCDCAuth) {
            if (colType == COL_CDCVAL_PRE) {
              txt = QString::fromLocal8Bit(
                  CBondCDCPriceInfo::instance()
                      .GetCDCPriceYesterday(nOptType, hasCDCAuth, bid,
                                            CBondCDCPriceInfo::price_type_yield,
                                            false)
                      .c_str());
            } else {
              txt = QString::fromLocal8Bit(
                  CBondCDCPriceInfo::instance()
                      .GetCDCPriceToday(nOptType, hasCDCAuth, bid,
                                        CBondCDCPriceInfo::price_type_yield,
                                        false)
                      .c_str());
            }

            if (txt.isEmpty()) {
              txt = "--";
            }
          } else {
            txt = "";
          }

          switch (nOptType) {
            case CBondCDCPriceInfo::est_type_combine:
            case CBondCDCPriceInfo::est_type_exercise:
            case CBondCDCPriceInfo::est_type_expire: {
              item->setData(NewStringTable::strEstRemark(nOptType + 1),
                            Qt::ToolTipRole);
              item->setData(BondUtility::gridImage(grid_flag_triangle),
                            Qt::DecorationRole);
            }
            default:
              break;
          }

          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_DEAL_CDC: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = BondUtility::getTakenCdcStr(
              GetCleanPrice(Body, &bondInfo).toLocal8Bit(), bid, hasCDCAuth);
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CDC_CLEANPRICE: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = "";
          int nOptType = CBondCDCPriceInfo::est_type_invalid;
          if (hasCDCAuth) {
            txt = QString::fromLocal8Bit(
                CBondCDCPriceInfo::instance()
                    .GetCDCPriceYesterday(nOptType, hasCDCAuth, bid,
                                          CBondCDCPriceInfo::price_type_clean,
                                          false)
                    .c_str());
          }

          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_DURATION: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = "";
          int nOptType = CBondCDCPriceInfo::est_type_invalid;
          if (hasCDCAuth) {
            txt = QString::fromLocal8Bit(
                CBondCDCPriceInfo::instance()
                    .GetCDCPriceYesterday(
                        nOptType, hasCDCAuth, bid,
                        CBondCDCPriceInfo::price_type_duration, false)
                    .c_str());
          }

          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_ISSUER_RATE: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetIssuerRating());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_BOND_RATE: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetBondRating());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CDC_RATING: {
          if (SSUserAccountManager::instance().HasAuthOfCDC()) {
            QString txt = "--";

            if (strlen(bondInfo.GetCDCRating()) == 0 ||
                strcmp(bondInfo.GetCDCRating(), "CCL") == 0) {
              txt = "--";
            } else {
              txt = QString::fromLocal8Bit(bondInfo.GetCDCRating());
            }

            item->setData(txt, Qt::DisplayRole);
          }
        } break;
        case COL_CSI_RATING: {
          if (SSUserAccountManager::instance().HasAuthOfCSI()) {
            QString txt = "--";

            if (strlen(bondInfo.GetCSIRating()) == 0 ||
                strcmp(bondInfo.GetCSIRating(), "CCL") == 0) {
              txt = "--";
            } else {
              txt = QString::fromLocal8Bit(bondInfo.GetCSIRating());
            }

            item->setData(txt, Qt::DisplayRole);
          }
        } break;
        case COL_CBR_RATING: {
          if (SSUserAccountManager::instance().HasAuthOfCBR()) {
            QString txt = "--";

            if (strlen(bondInfo.GetCBRRating()) == 0 ||
                strcmp(bondInfo.GetCBRRating(), "CCL") == 0) {
              txt = "--";
            } else {
              txt = QString::fromLocal8Bit(bondInfo.GetCBRRating());
            }

            item->setData(txt, Qt::DisplayRole);
          }
        } break;
        case COL_OUTLOOK: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetOutlookName());
          if (txt.isEmpty() || txt.compare("无") == 0) {
            txt = "--";
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CSIVAL: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = "";
          if (SSUserAccountManager::instance().GetCSIAuthorityFlag()) {
            UINT nType = 0;
            txt = QString::fromLocal8Bit(
                qb::biz::csi::FmtYield(bondInfo.GetCombBondKey(), nType)
                    .c_str());
            if (txt.isEmpty()) {
              txt = "--";
            }

            switch (nType) {
              case CBondCSInfo::emCSITypeCombine:
              case CBondCSInfo::emCSITypeExercise: {
                item->setData(NewStringTable::strEstRemark(nType - 1),
                              Qt::ToolTipRole);
                item->setData(BondUtility::gridImage(grid_flag_triangle),
                              Qt::DecorationRole);
              } break;
              case CBondCSInfo::emCSITypeMaturity:
              default:
                break;
            }
          } else {
            txt = "";
          }

          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_DEAL_CSI: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = "";
          if (SSUserAccountManager::instance().GetCSIAuthorityFlag()) {
            txt = QString::fromLocal8Bit(
                qb::biz::csi::FmtDealMinusCSI(
                    bondInfo.GetCombBondKey(),
                    std::string(GetCleanPrice(Body, &bondInfo).toLocal8Bit()))
                    .c_str());
            if (txt.isEmpty()) txt = "--";
          } else {
            txt = "";
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CSI_CLEANPRICE: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt = "";
          if (SSUserAccountManager::instance().GetCSIAuthorityFlag()) {
            txt = QString::fromLocal8Bit(
                qb::biz::csi::FmtCleanPrice(bondInfo.GetCombBondKey()).c_str());
            if (txt.isEmpty()) txt = "--";
          } else {
            txt = "";
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_OPTION_TYPE: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetOptionTypeName());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_OPTION_DATE: {
          QString txt = "";
          int nDate = atoi(bondInfo.GetOptionDate());
          if (nDate > 0) {
            txt = QString("%1-%2-%3")
                      .arg(nDate / 10000, 4, 10, QLatin1Char('0'))
                      .arg((nDate % 10000) / 100, 2, 10, QLatin1Char('0'))
                      .arg((nDate % 100), 2, 10, QLatin1Char('0'));
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_MATURITY_DATE: {
          QString txt = "";
          int nDate = atoi(bondInfo.GetMaturityDate());
          if (nDate > 0) {
            txt = QString("%1-%2-%3")
                      .arg(nDate / 10000, 4, 10, QLatin1Char('0'))
                      .arg((nDate % 10000) / 100, 2, 10, QLatin1Char('0'))
                      .arg((nDate % 100), 2, 10, QLatin1Char('0'));
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_TERM_TO_MATURITY: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetTermToMaturity());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CROSSMARKET: {
          QString txt = "";
          if (bondInfo.GetCrossmarket() == 'Y' ||
              bondInfo.GetCrossmarket() == 'y')
            txt = "是";
          else if (bondInfo.GetCrossmarket() == 'N' ||
                   bondInfo.GetCrossmarket() == 'n')
            txt = "否";
          else
            txt = QString(bondInfo.GetCrossmarket());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_INDUSTRY: {
          QString txt = QString::fromLocal8Bit(bondInfo.GetSwSector());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_RATINGAGENCY: {
          QString txt =
              QString::fromLocal8Bit(bondInfo.GetRatingInstitutionShortName());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_BOND_GUARANTOR: {
          QString txt = QString::fromLocal8Bit(
              qb::biz::BuildGuarantorName(bondInfo.GetWarranter(), false)
                  .c_str());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_OUTSTANDING_AMOUNT: {
          item->setData((int)(Qt::AlignRight | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          double fAmount = bondInfo.GetOutstandingAmount();
          QString txt = "";
          if (fAmount < 0.0001) {
            txt = "--";
          } else {
            txt = QString::number(fAmount / 100000, 'f', 2);
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
          /*	case COL_ACTUAL_ISSUE_AMOUNT:
                  {
                          item->setData((int)(Qt::AlignRight |
             Qt::AlignVCenter), Qt::TextAlignmentRole); double fAmount =
             bondInfo.GetActualIssueAmount(); QString txt = ""; if (fAmount <
             0.0001)
                          {
                                  txt = "--";
                          }
                          else
                          {
                                  txt = QString::number(fAmount / 10000, 'f',
             2);
                          }
                          item->setData(txt, Qt::DisplayRole);
                  }
                  break;*/
        case COL_ISSUE_TYPE:  // 发行
        {
          item->setData((int)(Qt::AlignLeft | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt;
          if (!bondInfo.is_interest_bond() &&
              strcmp(bondInfo.GetAssetStatus(), "PRI") != 0 &&
              strcmp(bondInfo.GetAssetStatus(), "PUB") != 0) {
            txt = NewStringTable::strFilterAssetStatus(1);  // 公募
          } else if (strcmp(bondInfo.GetAssetStatus(), "PUB") == 0) {
            txt = NewStringTable::strFilterAssetStatus(2);  // 小公募
          } else if (strcmp(bondInfo.GetAssetStatus(), "PRI") == 0) {
            txt = NewStringTable::strFilterAssetStatus(3);  // 私募
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_MUNICIPAL_BOND:  // 地方债类型
        {
          item->setData((int)(Qt::AlignLeft | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
          QString txt;
          if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0 &&
              strcmp(bondInfo.GetEntCor(), "SMB") == 0) {
            txt = NewStringTable::strFilterLocalBond(1);  // 一般债
          } else if (strcmp(bondInfo.GetBondSubType(), "LLB") == 0 &&
                     strcmp(bondInfo.GetEntCor(), "NMB") == 0) {
            txt = NewStringTable::strFilterLocalBond(2);  // 专项债
          }
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_BOND_TYPE: {
          QString txt = QString::fromStdString(
              qb::biz::BuildBondTypeName(bondInfo.GetBondSubType(),
                                         bondInfo.GetEntCor(), false)
                  .c_str());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_BOND_ISSUER: {
          QString txt = QString::fromLocal8Bit(
              qb::biz::BuildIssuerName(bondInfo.GetIssuerCode(), false)
                  .c_str());
          item->setData(txt, Qt::DisplayRole);
        } break;
        case COL_CORP: {
          if (m_nCorpID == 0) {
            int nCurBroker = atoi(msi.m_company_id);
            if (CBrokerList::IsValidBroker(nCurBroker)) {
              item->setData(nCurBroker, BrokerIdRole);
            }
          }
        }

        break;
        case COL_UPDATETIME: {
          time_t t_Current = msi.m_modify_time;
          BondUtility::SetUpdateTimeCol(item, t_Current);
          item->setData(timeF, Qt::FontRole);
          item->setData((int)(Qt::AlignCenter | Qt::AlignVCenter),
                        Qt::TextAlignmentRole);
        } break;
        default:
          break;
      }
      m_model->setItem(row, col, item);
    }
  }

  m_dealTable->startFlash();
}

void RealDealTable::updateSpecialListWidth() {
  if (!m_tableSet) return;

  if (m_nCorpID == 0) {
    m_tableSet->setColumnHide(COL_CORP, false);
  } else if (CBrokerList::IsValidBroker(m_nCorpID)) {
    m_tableSet->setColumnHide(COL_CORP, true);
  }
}

void RealDealTable::resizeEvent(QResizeEvent* event) {
  QWidget::resizeEvent(event);

  updateSpecialListWidth();
}

void RealDealTable::onDealMarketPushAll(int funcId,
                                        QList<xQBMarketStreamUnit_c> mks) {
  updateTable();
}

void RealDealTable::onHeaderSort(int col) { sortHeader(col, false); }

void RealDealTable::sortHeader(int col, bool desc, bool reset) {
  int sortKey = getSortKey(m_cols[col], false);
  if (sortKey != VBOND_NULL) {
    bool bPressCtrl =
        qApp->queryKeyboardModifiers().testFlag(Qt::ControlModifier);

    if (reset) {
      m_dealModel->GetSortInfo().InitData();
    }

    m_dealModel->GetSortInfo().AddOrUpdate(bPressCtrl, sortKey, desc);

    DefaultTableModel* dataModel =
        dynamic_cast<DefaultTableModel*>(m_dealTable->table()->model());
    for (size_t i = 0; i < m_cols.size(); ++i) {
      CSortInfo sortinfo;
      ColumnInfo ci = m_tableSet->colInfoByIndex(i);
      if (m_dealModel->GetSortInfo().GetSortInfo(getSortKey(m_cols[i], false),
                                                 sortinfo)) {
        QString preFix = sortinfo.m_bDesc ? "↓ " : "↑ ";
        dataModel->setHeaderData(i, Qt::Horizontal, preFix + ci.name);
      } else
        dataModel->setHeaderData(i, Qt::Horizontal, ci.name);
    }

    if (m_dealModel->GetSortInfo().GetSize() > 0) {
      m_selRowKey.clear();
      m_dealModel->OnSort();
      updateTable(true);
    }
  }
}

void RealDealTable::onBrokerSelChanged() {
  for (int i = 0; i < (int)m_cols.size(); ++i) {
    if (COL_UPDATETIME == m_cols[i]) {
      sortHeader(i, false);
      sortHeader(i, true);
      break;
    }
  }
}

void RealDealTable::onContextMenu(QPoint pos) {
  QModelIndex index = m_dealTable->table()->currentIndex();

  int mouseRow = index.row();
  DealIndex id;

  m_dealModel->GetCacheId(mouseRow + 1, id);
  m_dealModel->GetCacheRecord(id, *m_dealRecord);

  int bid = CBondContainer::instance().GetBondIndex(
      m_dealRecord->m_body.m_bondkey, m_dealRecord->m_body.m_listedmarket);
  if (!CBondContainer::instance().IsValidIndex(bid)) return;
  *m_dealIndex = CBondContainer::instance().ElementAtR(bid);

  FormatDealToClipBoard(m_dealRecord->m_company_id,
                        QString::fromLocal8Bit(m_dealIndex->GetCombBondKey()),
                        m_dealCopyData, CSSVContainer::GetServerTime(),
                        *m_dealRecord, !id.id.empty(), false);

  QMenu* menu = new QMenu(this);
  menu->setAttribute(Qt::WA_DeleteOnClose);

  menu->addAction(tr("债券详情"), this, [=]() { onMenuClick(BondDetial); });

  QMenu* smallMenu = menu->addMenu(tr("弹出小窗"));
  smallMenu->setEnabled(false);
  smallMenu->addAction(tr("行情小窗"), this,
                       [=]() { onMenuClick(QuotationWindow); });
  smallMenu->addAction(tr("利差小窗"), this,
                       [=]() { onMenuClick(MarginWindow); });

  menu->addAction(tr("相似债券"), this, [=]() { onMenuClick(BondSimilar); });

  QMenu* calculatorMenu = menu->addMenu(tr("计算器"));
  calculatorMenu->setEnabled(false);
  calculatorMenu->addAction(tr("债券价格试算"), this,
                            [=]() { onMenuClick(TrialCalculatin); });
  calculatorMenu->addAction(tr("持有期收益"), this,
                            [=]() { onMenuClick(HoldCalculatin); });

  menu->addAction(tr("复制债券简称"), this,
                  [=]() { onMenuClick(CopyBondShortName); });
  menu->addAction(tr("复制价格"), this, [=]() { onMenuClick(CopyPrice); });

  QAction* action1 = new QAction(menu);
  action1->setText(tr("添加至默认关注"));
  action1->setEnabled(false);
  menu->addAction(action1);

  QAction* action2 = new QAction(menu);
  action2->setText(tr("添加至关注"));
  action2->setEnabled(false);
  menu->addAction(action2);

  QAction* action3 = new QAction(menu);
  action3->setText(tr("设置债券提醒"));
  action3->setEnabled(false);
  menu->addAction(action3);

  // menu->addAction(tr("添加至默认关注"), this, [=]()
  // {onMenuClick(AddDefaultFollow); }); menu->addAction(tr("添加至关注"), this,
  // [=]() {onMenuClick(AddFollow); }); menu->addAction(tr("设置债券提醒"),
  // this, [=]() {onMenuClick(SetBondReminder); });

  if (m_dealTable->table()->isVisible()) {
    menu->popup(QCursor::pos());
  }
}

void RealDealTable::onMenuClick(tipsMenu index) {
  const CBondInfo& bond = *m_dealIndex;
  MarketStreamInfo record = *m_dealRecord;

  switch (index) {
    case BondDetial: {
      if (bond.IsValidBond()) {
        QbBondModule::instance().app()->execCommand(CMD_BondDetail,
                                                    bond.GetCombBondKey());

        IMainFrame* frame = QbBondModule::instance().app()->mainFrame();
        int tabId =
            frame->existCmdWindow(CMD_BondDetail, bond.GetCombBondKey());
        if (tabId != -1) {
          QWidget* widget = nullptr;

          widget = frame->cmdWindow(tabId);

          BondDetailDlg* ptr = dynamic_cast<BondDetailDlg*>(widget);
          ptr->setBroker(atoi(record.m_company_id));

          frame->activateCmdWindow(tabId);
        }
      }
    } break;
    case QuotationWindow:
    case MarginWindow:
    case BondSimilar: {
      QString param = QString::fromLocal8Bit(bond.GetCombBondKey());
      param.append("|").append("RELATED");

      QbBondModule::instance().app()->execCommand(CMD_WebBondDetail_Profile,
                                                  param.toUtf8());
    } break;
    case TrialCalculatin:
    case HoldCalculatin:
    case CopyBondShortName: {
      QClipboard* pClip = QApplication::clipboard();
      pClip->clear();
      pClip->setText(QString::fromLocal8Bit(bond.GetBondShortName()));
    } break;
    case CopyPrice: {
      QClipboard* pClip = QApplication::clipboard();
      pClip->clear();
      pClip->setText(m_dealCopyData);
    } break;
    case AddDefaultFollow:
    case AddFollow:
    case SetBondReminder:
    default:
      break;
  }
}

void RealDealTable::onRealDealRowClicked(const QModelIndex& index) {
  updateTable(false, index.row());
}

void RealDealTable::onRealDealRowDblClicked(const QModelIndex& index) {
  if (nullptr == m_dealTable) {
    return;
  }

  int pageCount = m_dealTable->pageCount();
  int pos = m_dealTable->sliderPos();

  MarketStreamInfo records[256];
  int count = m_dealModel->GetRecords(pos, pageCount, records);

  const MarketStreamInfo& msi = records[index.row()];
  int bid = CBondContainer::instance().GetBondIndex(msi.m_body.m_bondkey,
                                                    msi.m_body.m_listedmarket);
  if (!CBondContainer::instance().IsValidIndex(bid)) return;
  const CBondInfo& bondInfo = CBondContainer::instance().ElementAtR(bid);

  QbBondModule::instance().app()->execCommand(CMD_BondDetail,
                                              bondInfo.GetCombBondKey());

  IMainFrame* frame = QbBondModule::instance().app()->mainFrame();
  int tabId = frame->existCmdWindow(CMD_BondDetail, bondInfo.GetCombBondKey());
  if (tabId != -1) {
    QWidget* widget = nullptr;

    widget = frame->cmdWindow(tabId);

    BondDetailDlg* ptr = dynamic_cast<BondDetailDlg*>(widget);
    ptr->setBroker(atoi(msi.m_company_id));

    frame->activateCmdWindow(tabId);
  }
}
